/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ai;

import ai.io.DataSource;
import java.awt.Dimension;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Random;
import ai.gui.LayoutHint;

/**
 *
 * @author pjl
 */
public class AIModel implements Progressable {

    Brain brain;
    private Dimension dimImage;
    private String statusString;
    private DataSource trainSrc;
    private DataSource testSrc;
    private Result result;
    private float progress;
    Random rand = new Random();
    private boolean stop;
    private boolean dispose;

    public AIModel(Brain brain, DataSource training, DataSource test) throws FileNotFoundException, IOException, Exception {
        this.trainSrc = training;
        this.testSrc = test;
        dimImage = trainSrc.getInDimension();
        Dimension dimensionOut = trainSrc.getOutDimension();
        this.brain=brain;
        result = new Result(dimImage, dimensionOut);
    }

    public void dispose() {
        System.out.println(" Disposing  . . . . . ");
       dispose=true;
       stop=true;
    }

    public void dump() {
        brain.dump(); //throw new UnsupportedOperationException("Not yet implemented");
    }

    public Brain getBrain() {
        return brain;
    }

    public void allTraining() {
        //  statusString = "Training";

        if (brain instanceof BatchTrainable) {
            ((BatchTrainable) brain).doBatchTrain(trainSrc);
        } else {
            int maxx = trainSrc.getSize(); // trainingReader.getSizes()[0];
            for (int i = 0; i < maxx; i++) {

                DataSource.Data data = trainSrc.getData(i);
                brain.setTrain(data);
                brain.getLatestResult(result);
                progress = (float) (i) / maxx;
                if (stop || dispose) {
                    break;
                }
            }
        }
        //  statusString = "Done";
        stop = false;
        brain.notifyObservers();

    }

    public void allTest() {
        statusString = "Testing";
        int maxx = testSrc.getSize();
        int right = 0;
        int wrong = 0;

        for (int i = 0; i < maxx; i++) {
            doTest(i);


            brain.getLatestResult(result);


            progress = ((float) i) / maxx;
            int guess = -1;
            float maxV = 0.0f;

            for (int k = 0; k < 10; k++) {
                if (result.out.label[k] > maxV) {
                    maxV = result.out.label[k];
                    guess = k;
                }
            }

            if (guess == Util.toLabel(result.in.label)) {
                right++;
            } else {
                wrong++;
            }
            if (stop || dispose ) {
                break;
            }
        }

        statusString = "Correct: " + (float) right * 100.0 / maxx + "%";
        stop = false;
        brain.notifyObservers();
    }

    public Dimension getImageDimension() {
        return dimImage;
    }

    public LayoutHint getLayoutHint() {
        if (brain instanceof LayoutHinter) {
            return ((LayoutHinter) brain).layoutHint();
        }
        return new LayoutHint(10);
    }

    public void nextMiss() {
        int maxx = testSrc.getSize(); //[0];
        long count = 0;
        do {
            doTest((testCount++)%maxx);
            if(stop || dispose) break;
        } while (Util.toLabel(result.out.label) == Util.toLabel(result.in.label) && count++ < maxx);
        brain.getLatestResult(result);
    }

    int trainCount=0;
    int testCount=0;
    
    public void doTrain(int index) {

        statusString = "Training";
      //  int maxx = trainSrc.getSize(); // trainingReader.getSizes()[0];
//        int index = rand.nextInt(maxx);
        DataSource.Data data = trainSrc.getData(index);
        brain.setTrain(data);
  
        brain.getLatestResult(result);
        brain.notifyObservers();

    }

    public void nextTrain() {
        doTrain(trainCount++);     
    }
 
    public void nextTest() {

      //  System.out.println(" NEXT TEST");
        int maxx = testSrc.getSize(); //[0];
  
        doTest((testCount++)%maxx);
        
        brain.getLatestResult(result);
        brain.notifyObservers();

    }

    public Result getLatestResult() {
        return result;
    }
//    Dimension getDimension() {
//        return dimension;
//    }
    private void doTest(int index) {

        DataSource.Data data = testSrc.getData(index);

        brain.fire(data);
        brain.getLatestResult(result);
    }

    public String getStatusString() {
        return statusString;
    }

    public float getProgress() {
        return progress;
    }

    public void stop() {
        stop = true;
    }
}

